#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <sys/poll.h>
#include <string.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>

#define MAX_CLIENT 20

void send_all(struct pollfd * fds, const char *msg, int myself){
    for(int i=1;i<MAX_CLIENT;i++){
        if(fds[i].fd == -1) continue;

        //if(fds[i].fd != myself){  // 不给自己发消息
            write(fds[i].fd, msg, strlen(msg));
        //}
    }
}

// ./bbs <port>
int main(int argc, char const *argv[])
{
    if(argc !=2 ) return -1;

    struct pollfd fds[MAX_CLIENT+1];  // 所有套字节

    fds[0].fd = socket(AF_INET, SOCK_STREAM, 0);
    fds[0].events = POLLIN; 

    struct sockaddr_in server_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(atoi(argv[1])),
        .sin_addr.s_addr = INADDR_ANY
    };

    if(bind(fds[0].fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) !=0){
        perror("bind");
        return -1;
    }

    listen(fds[0].fd,20);
    printf("BBS(%s) Runing...\n", argv[1]);

    // 初始化pollfd
    int i=1, c = 1; // c 表示pollfd的可用个数

    for(;i<MAX_CLIENT; i++){
        fds[i].fd = -1;  // 未使用
    }

    char buf[512] = ""; // 缓冲区

    // 定义客户端的IP地址
    char ips[MAX_CLIENT][16] ; 
    char names[MAX_CLIENT][32]; // 用户名

    while (1)
    {
        if(poll(fds, c, -1) < 0){
            printf("Server Error\n");
            break;
        }

        if(fds[0].revents & POLLIN){  // 有客户端连接了
            struct sockaddr_in client_addr;
            socklen_t client_addr_len = sizeof(client_addr);

            int client_fd = accept(fds[0].fd, (struct sockaddr*)&client_addr, &client_addr_len);
            if(client_fd > 0){
                for(i=1; i<MAX_CLIENT; i++){
                    if(fds[i].fd == -1){
                        fds[i].fd = client_fd;
                        fds[i].events = POLLIN; // 客户端发送数据时的事件【可读】

                        c++;
                        inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ips[i-1], 16);
                        bzero(names[i-1], 32); // 清空用户名
                        break;
                    }
                }
            }
        }
        

        // 处理客户端的数据
        for(i=1;i<MAX_CLIENT;i++){
            if(fds[i].fd == -1) continue;

            if(fds[i].revents & POLLIN){
                char tmpbuf[128] = "";
                if(read(fds[i].fd, tmpbuf, 128) > 0){

                   if( strlen(names[i-1]) == 0){
                       // 第一次接收数据
                        // 接收的是用户名
                        strncpy(names[i-1], tmpbuf, strlen(tmpbuf));
                        sprintf(buf, "%s(%s): 进入聊天室",names[i-1], ips[i-1]);
                       
                   }else{
                    sprintf(buf, "%s(%s): %s",names[i-1], ips[i-1], tmpbuf);
                   }
                    
                    send_all(fds, buf, fds[i].fd);  // 发送给所有客户端
                    bzero(buf, 512);
                }else{
                    // 关闭客户端连接，重置-1，让给其它客户端连接使用
                    close(fds[i].fd);
                    fds[i].fd = -1;
                }
            }
        }

    }
    

    // 清理客户端信息
    for(i=0;i<MAX_CLIENT;i++){
        if(fds[i].fd != -1) close(fds[i].fd);
    }
    return 0;
}